package org.mozhu.mboot.core.data;

import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.mozhu.mboot.core.data.filter.GroupSearchFilter;
import org.mozhu.mboot.core.data.filter.Operator;
import org.mozhu.mboot.core.data.filter.SearchFilter;
import org.mozhu.mboot.core.data.filter.SimpleSearchFilter;
import org.mozhu.mboot.core.web.Servlets;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class SearchFilters {

    public static final String DEFAULT_SEARCH_PREFIX = "search_";
    /**
     * 多个属性间OR关系的分隔符.
     */
    public static final String OR_SEPARATOR = "_OR_";
    public static final String UNDERLINE_SEPARATOR = "_";

    public static List<SearchFilter> parse(HttpServletRequest request, String prefix) {
        Map<String, Object> searchParams = Servlets.getParametersStartingWith(request, prefix);
        Map<String, SearchFilter> filters = SearchFilters.parse(searchParams);
        return Lists.newArrayList(filters.values());
    }

    public static List<SearchFilter> parse(HttpServletRequest request) {
        return parse(request, DEFAULT_SEARCH_PREFIX);
    }

    /**
     * search_LIKE_name_OR_loginName<br/>
     * search_GT_age searchParams中key的格式为OPERATOR_FIELDNAME
     */
    public static Map<String, SearchFilter> parse(Map<String, Object> searchParams) {
        Map<String, SearchFilter> filters = Maps.newHashMap();

        for (Entry<String, Object> entry : searchParams.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            SearchFilter searchFilter = createFilter(key, value);
            // 过滤掉空值
            if (searchFilter != null) {
                filters.put(key, searchFilter);
            }
        }

        return filters;
    }

    public static SearchFilter createFilter(String key, Object value) {
        // 过滤掉空值
        int indexOf = key.indexOf(UNDERLINE_SEPARATOR);
        if (indexOf <= 0) {
            throw new IllegalArgumentException(key + " is not a valid search filter name");
        }

        if (value == null) {
            return null;
        }

        if (value instanceof String && StringUtils.isBlank((String) value)) {
            return null;
        }

        String operatorString = key.substring(0, indexOf);
        Operator operator = Operator.valueOf(operatorString.toUpperCase());

        String propertyNameString = key.substring(indexOf + UNDERLINE_SEPARATOR.length(), key.length());
        if (propertyNameString.contains(OR_SEPARATOR)) {
            return createFilter(Lists.newArrayList(Splitter.on(OR_SEPARATOR).split(propertyNameString)), operator, value);
        } else {
            return createFilter(propertyNameString, operator, value);
        }
    }

    public static SearchFilter createFilter(List<String> propertyNames, Operator operator, Object value) {
        List<SearchFilter> searchFilters = Lists.newArrayList();
        for (String propertyName : propertyNames) {
            searchFilters.add(createFilter(propertyName, operator, value));
        }
        return GroupSearchFilter.or(searchFilters);
    }

    public static SearchFilter createFilter(String propertyName, Operator operator, Object value) {
        return new SimpleSearchFilter(propertyName, operator, value);
    }

    public static SearchFilter createFilter(String propertyName, Operator operator, Object[] value) {
        return new SimpleSearchFilter(propertyName, operator, value);
    }

    public static Sort createSort(final Sort.Direction direction, String property) {
        return Sort.by(new Order(direction, property));
    }

    public static SearchFilter and(Collection<SearchFilter> searchFilters) {
        return GroupSearchFilter.and(searchFilters);
    }

    public static SearchFilter or(Collection<SearchFilter> searchFilters) {
        return GroupSearchFilter.or(searchFilters);
    }

    public static SearchFilter and(SearchFilter... searchFilters) {
        return GroupSearchFilter.and(searchFilters);
    }

    public static SearchFilter or(SearchFilter... searchFilters) {
        return GroupSearchFilter.or(searchFilters);
    }

    public static String getKey(String propertyName, Operator operator) {
        return operator.name() + UNDERLINE_SEPARATOR + propertyName;
    }
}
